import { Platform } from '@antv/x6';
import { Portal } from '@antv/x6-react-shape';
import { Background, EdgeOptions, GraphOptions, Grid, History, NodeOptions, Snapline, XFlow, XFlowGraph } from '@antv/xflow';
import { FC } from 'react';

import { colors } from '@/config/theme';
import { NODE_TYPE } from '@/constants/config';
import { useInteracting } from '@/hooks/useGraph';
import { registerEdge } from '@/utils/graph';

import { EdgeDrawer } from '../EdgeDrawer';
import { GraphInit } from './init';

interface GraphContainerProps {
  graphJson?: { nodes: NodeOptions[]; edges: EdgeOptions[] };
  mode: 'edit' | 'view';
  children?: React.ReactNode;
}

/** fix: https://x6.antv.antgroup.com/tutorial/intermediate/react */
const X6ReactPortalProvider = Portal.getProvider();

export const GraphContainer: FC<GraphContainerProps> = memo((props) => {
  const { interacting } = useInteracting();
  const connectionOptionsRef = useRef<GraphOptions['connectionOptions']>({
    snap: true,
    allowBlank: false,
    allowLoop: false,
    highlight: true,
    connectionPoint: 'anchor',
    anchor: 'center',
    validateMagnet({ magnet }) {
      return magnet.getAttribute('port-group') !== 'in';
    },
    validateConnection({ sourceMagnet, targetMagnet }) {
      // 只能从输出连接桩创建连接
      if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
        return false;
      }

      // 只能连接到输入连接桩
      if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
        return false;
      }

      return true;
    },
    sourceAnchor: {
      name: 'left',
      args: {
        dx: Platform.IS_SAFARI ? 4 : 8
      }
    },
    targetAnchor: {
      name: 'right',
      args: {
        dx: Platform.IS_SAFARI ? 4 : -8
      }
    }
  });

  useEffect(() => {
    registerEdge();
  }, []);

  return (
    <div className="graph-container flex bg-fill-2 rounded-8px flex flex-col w-full h-full">
      <XFlow>
        <X6ReactPortalProvider />
        <EdgeDrawer />
        {props.children}
        <GraphInit graphJson={props.graphJson} />
        <XFlowGraph
          readonly={interacting === false}
          connectionOptions={connectionOptionsRef.current}
          zoomable
          pannable
          minScale={0.5}
          connectionEdgeOptions={{
            shape: NODE_TYPE.BASE_EDGE,
            connector: { name: 'smooth' },
            attrs: {
              line: {
                strokeDasharray: 5,
                strokeWidth: 1.1,
                targetMarker: 'classic',
                style: {
                  animation: 'ant-line 12s infinite linear'
                }
              }
            },
            defaultLabel: {
              markup: [
                {
                  tagName: 'rect',
                  selector: 'body'
                },
                {
                  tagName: 'text',
                  selector: 'label'
                }
              ],
              attrs: {
                text: {
                  fill: colors.blue[600],
                  fontSize: 12,
                  textAnchor: 'middle',
                  textVerticalAnchor: 'middle'
                },
                rect: {
                  ref: 'label',
                  fill: colors.blue[100],
                  stroke: colors.blue[400],
                  refWidth: 14,
                  refHeight: 5,
                  refX: -7,
                  refY: -2.5,
                  rx: 20
                }
              },
              position: {
                distance: 0.5
              }
            },
            zIndex: -1
          }}
        />
        <History
          beforeAddCommand={(_, args: any) => {
            return args?.key !== 'tools';
          }}
        />
        <Snapline />
        <Grid
          type="fixedDot"
          options={{
            color: colors.gray[200],
            thickness: 1
          }}
        />
        <Background color={colors.gray[50]} />
      </XFlow>
    </div>
  );
});
